package com.gitee.proxy.handler.proxy;

import com.gitee.proxy.server.ServerConfig;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.ReferenceCountUtil;

public class ProxyHttpRequestDataHandler {

    private ServerConfig serverConfig;

    private Object lock = new Object();

    public ProxyHttpRequestDataHandler(ServerConfig serverConfig) {
        this.serverConfig = serverConfig;
    }

    public void handleConnectData(ChannelHandlerContext ctx, Object msg) {
        HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
        ctx.writeAndFlush(response);
        ctx.channel().pipeline().remove("httpServerCodec");
        ReferenceCountUtil.release(msg);
    }

    public void handleProxyData(final ChannelHandlerContext ctx, final ProxyHttpRequest request, Object currentMsg) {
        if (request.getClientChannelFuture() != null) {
            if (request.isConnect()) {
                request.getClientChannelFuture()
                        .channel()
                        .writeAndFlush(currentMsg);
            } else {
                synchronized (lock) {
                    request.getMsgList().add(currentMsg);
                }
            }
            return;
        }

        // 使用netty客户端转发请求
        ChannelInitializer clientInitializer = request.isHttps() ? new HttpsProxyClientInitalizer(ctx.channel()) : new HttpProxyClientInitalizer(ctx.channel());
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(serverConfig.getProxyLoopGroup())
                .channel(NioSocketChannel.class)
                .handler(clientInitializer);
        ChannelFuture cf = bootstrap.connect(request.getHost(), request.getPort());
        request.setClientChannelFuture(cf);
        cf.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                System.out.println(future);
                if (future.isSuccess()) {
                    // 发送请求
                    request.setConnect(true);
                    request.getClientChannelFuture()
                            .channel()
                            .writeAndFlush(currentMsg);
                    synchronized (lock) {
                        request.getMsgList().stream().forEach(e ->
                                request.getClientChannelFuture()
                                        .channel()
                                        .writeAndFlush(e)
                        );
                    }
                    request.getMsgList().clear();
                } else {
                    request.getMsgList().stream().forEach(e -> ReferenceCountUtil.release(e));
                    request.getMsgList().clear();
                    future.channel().close();
                    ctx.channel().close();
                }
            }
        });
    }
}
